package com.knife.scheduler.domain.service.impl;

import com.knife.common.constants.BaseConstants;
import com.knife.common.exception.CommonException;
import com.knife.scheduler.domain.entity.KnifeJobInfo;
import com.knife.scheduler.domain.service.KnifeJobService;
import com.knife.scheduler.infra.constants.KnifeSchedulerConstant;
import com.knife.scheduler.infra.job.KnifeJobDetail;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.util.Date;
import java.util.Objects;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

/**
 * 创建/更新定时任务
 *
 * @author： 76875
 * @date： 2022/4/2 星期六 17:13
 * @description：
 * @modifiedBy：
 * @version: 1.0
 */
@Service
public class KnifeJobServiceImpl implements KnifeJobService, KnifeSchedulerConstant {

    @Autowired
    private Scheduler scheduler;

    @Override
    public void createJob(KnifeJobInfo knifeJobInfo) {
        try {
            if (ObjectUtils.isEmpty(knifeJobInfo)) {
                return;
            }
            // 创建工作
            JobDetail jobDetail = JobBuilder.newJob(KnifeJobDetail.class)
                    .withDescription(knifeJobInfo.getDescription())
                    .withIdentity(knifeJobInfo.getQuartzName(), knifeJobInfo.getQuartzGroup())
                    .usingJobData(getMap(knifeJobInfo))
                    .build();
            // 触发器
            Trigger trigger = buildTrigger(knifeJobInfo);
            Assert.notNull(trigger, "触发器不能为空");
            if (scheduler.checkExists(jobDetail.getKey())) {
                // 更新触发器
                scheduler.rescheduleJob(trigger.getKey(), trigger);
            } else {
                // 新增任务
                scheduler.scheduleJob(jobDetail, trigger);
            }
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateJob(KnifeJobInfo knifeJobInfo) {
        try {
            if (ObjectUtils.isEmpty(knifeJobInfo)){
                return;
            }
            TriggerKey triggerKey = TriggerKey.triggerKey(knifeJobInfo.getQuartzName(), knifeJobInfo.getQuartzGroup());
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (!ObjectUtils.isEmpty(trigger)) {
                // 删除原有任务
                JobKey jobKey = JobKey.jobKey(knifeJobInfo.getQuartzName(), knifeJobInfo.getQuartzGroup());
                scheduler.pauseTrigger(triggerKey);
                scheduler.unscheduleJob(triggerKey);
                scheduler.deleteJob(jobKey);
                if (scheduler.checkExists(jobKey)) {
                    throw new CommonException("任务更新异常");
                } else {
                    // 添加任务
                    createJob(knifeJobInfo);
                }
            }else {
                // 任务不存在，直接创建新任务
                createJob(knifeJobInfo);
            }
        } catch (SchedulerException e) {
            throw new CommonException("任务更新异常", e);
        }
    }

    @Override
    public void pauseJob(KnifeJobInfo knifeJobInfo) {
        try {
            scheduler.pauseJob(JobKey.jobKey(knifeJobInfo.getQuartzName(), knifeJobInfo.getQuartzGroup()));
        } catch (Exception e) {
            throw new CommonException("暂停任务失败");
        }
    }

    /**
     * 构建任务参数
     */
    private JobDataMap getMap(KnifeJobInfo knifeJobInfo) {
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put(CODE, knifeJobInfo.getJobCode());
        return jobDataMap;
    }


    /**
     * 构建触发器
     *
     * @param knifeJobInfo 任务信息
     * @return 触发器
     */
    private Trigger buildTrigger(KnifeJobInfo knifeJobInfo) {
        TriggerKey triggerKey = TriggerKey.triggerKey(knifeJobInfo.getQuartzName(), knifeJobInfo.getQuartzGroup());
        Trigger trigger = null;
        Date start = knifeJobInfo.getStartDate();
        Date end = knifeJobInfo.getEndDate();

        if (Objects.equals(knifeJobInfo.getCycleFlag(), BaseConstants.Flag.YES)) {
            String cron = knifeJobInfo.getCron();
            // 若cron没有指定，使用默认cron，模拟永不自动执行
            if (StringUtils.isBlank(cron)) {
                cron = CRON;
            }
            // 创建周期任务触发器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing();
            if (start != null && end != null) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(cronScheduleBuilder)
                        .startAt(start)
                        .endAt(end)
                        .build();
            }
            if (start != null && end == null) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(cronScheduleBuilder)
                        .startAt(start)
                        .build();
            }
            if (start == null && end != null) {
                long currentTime = System.currentTimeMillis() + 30 * 1000;
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(cronScheduleBuilder)
                        .startAt(new Date(currentTime))
                        .endAt(end)
                        .build();
            }
            // 任务延迟30秒执行，留给quartz足够准备时间
            if (start == null && end == null) {
                long currentTime = System.currentTimeMillis() + 30 * 1000;
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(cronScheduleBuilder)
                        .startAt(new Date(currentTime))
                        .build();
            }
        } else {
            if (start == null) {
                // 创建瞬时任务触发器
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(simpleSchedule().withRepeatCount(0))
                        .startNow()
                        .build();
            } else {
                // 创建瞬时任务触发器
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(simpleSchedule().withRepeatCount(0))
                        .startAt(start)
                        .build();
            }

        }
        return trigger;
    }

}
